package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.factory.GuiguItemType;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.security.interfaces.RSAPrivateKey;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author GQS @Date 2024/11/11/9:14 @Description
 * 声音订单的实现类
 */
@Slf4j
@Service("trackOrderInfoServiceImpl")
@SuppressWarnings({"unchecked", "rawtypes"})
@GuiguItemType(itemType = SystemConstant.ORDER_ITEM_TYPE_TRACK)
public class TrackOrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

  @Resource
  private OrderInfoMapper orderInfoMapper;

  @Resource
  private OrderDetailMapper orderDetailMapper;

  @Resource
  private OrderDerateMapper orderDerateMapper;

  @Resource
  private TrackInfoFeignClient trackInfoFeignClient;

  @Resource
  private AlbumInfoFeignClient albumInfoFeignClient;

  @Resource
  public RSAPrivateKey rsaPrivateKey;

  @Resource
  private UserInfoFeignClient userInfoFeignClient;

  @Autowired
  private RedisTemplate redisTemplate;

  @Autowired
  private RabbitTemplate rabbitTemplate;

  // @Override
  // public String getItemType() {
  //   return SystemConstant.ORDER_ITEM_TYPE_TRACK;
  // }

  /**
   * 订单确认接口
   * @param tradeVo
   * @return
   */
  @Override
  public Object trade(TradeVo tradeVo) {
    // 获取购买的第一个声音的id
    Long itemId = tradeVo.getItemId();
    // 获取一共购买的声音的数量
    Integer trackCount = tradeVo.getTrackCount();
    // 查询当前声音所属的专辑的可以购买的声音列表
    List<TrackInfo> trackInfoList =
            trackInfoFeignClient.trackInfo(itemId, trackCount);
    if(trackInfoList == null || trackInfoList.isEmpty()){
      throw new GuiguException(201, "声音不存在!");
    }
    //获取专辑的id
    Long albumId = trackInfoList.get(0).getAlbumId();
    //查询专辑的数据
    AlbumInfo albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);
    //获取声音的单价
    BigDecimal price = albumInfo.getPrice();
    //包装订单对象: 不入库!!!!!!!!!!!!!!
    OrderInfoVo orderInfoVo = new OrderInfoVo();
    //交易号
    orderInfoVo.setTradeNo(IdWorker.get32UUID());
    //支付方式: 默认为微信
    orderInfoVo.setPayWay("1101");
    //购买的类型
    orderInfoVo.setItemType(SystemConstant.ORDER_ITEM_TYPE_TRACK);
    //原始金额
    orderInfoVo.setOriginalAmount(price.multiply(new BigDecimal(trackInfoList.size())));
    //订单金额 声音不享受折扣
    orderInfoVo.setOrderAmount(price.multiply(new BigDecimal(trackInfoList.size())));
    //减免金额
    orderInfoVo.setDerateAmount(new BigDecimal(0));
    //声明订单的明细对象
    List<OrderDetailVo> orderDetailVoList =
            trackInfoList.stream().map(t->{
              OrderDetailVo orderDetailVo = new OrderDetailVo();
              orderDetailVo.setItemId(t.getId());
              orderDetailVo.setItemName(t.getTrackTitle());
              orderDetailVo.setItemUrl(t.getCoverUrl());
              orderDetailVo.setItemPrice(price);
              return orderDetailVo;
            }).toList();
    orderInfoVo.setOrderDetailVoList(orderDetailVoList);
    //声明订单的减免详情--声音不打折
    orderInfoVo.setOrderDerateVoList(null);
    //时间戳
    orderInfoVo.setTimestamp(System.currentTimeMillis());
    //签名-JWT
    Jwt encode =
            JwtHelper.encode(JSONObject.toJSONString(orderInfoVo), new RsaSigner(rsaPrivateKey));
    orderInfoVo.setSign(encode.getEncoded());
    //返回订单对象
    return orderInfoVo;
  }

  /**
   * 提交订单: 写入数据库
   * @param orderInfoVo
   * @return
   */
  @Override
  public Object submitOrder(OrderInfoVo orderInfoVo) {
    // 获取当前登录用户id
    Long userId = AuthContextHolder.getUserId();
    // todo 获取支付方式 声音默认是余额支付-1103
    // String payWay = orderInfoVo.getPayWay();
    String payWay = "1101";
    // 用公钥尝试获取签名 成功则获取到载荷中的信息 失败则报异常
    String sign = orderInfoVo.getSign();
    try {
      Jwt jwt = JwtHelper.decodeAndVerify(sign, new RsaVerifier(SystemConstant.PUBLIC_KEY));
      // 获取载荷
      String claims = jwt.getClaims();
      // 反序列化 获得载荷中的信息
      orderInfoVo = JSONObject.parseObject(claims, OrderInfoVo.class);
    } catch (Exception e) {
      throw new GuiguException(201, "非法参数, 请重新下单");
    }
    // 1112 添加的逻辑 防止用户重复提交包含购买同一个声音的订单
    //获取第一条声音的id
    Long itemId = orderInfoVo.getOrderDetailVoList().get(0).getItemId();
    // 查询该声音的详细信息
    TrackInfo trackInfo = trackInfoFeignClient.getTrackInfo(itemId);
    // 获取专辑id
    Long albumId = trackInfo.getAlbumId();

      // 声音订单提交锁 防止用户重复提交订单  15分钟后自动过期
    if(redisTemplate.opsForValue().setIfAbsent(userId + "_" + albumId, "track", 15, TimeUnit.MINUTES)){
      // 查询该声音所在的专辑中用户已购买的声音
      Map<String, Object> userPaidMap =
              userInfoFeignClient.getUserPaidTrack(userId, albumId);
      // 对用户本次要购买的声音进行过滤
      orderInfoVo.getOrderDetailVoList().stream().forEach(orderDetailVo -> {
        //获取声音的id
        String trackId = orderDetailVo.getItemId().toString();
        // 判断已购买的声音列表中是否有本次要买的声音
        if(userPaidMap.get(trackId) != null){
          throw new GuiguException(201, "声音重复购买!!");
        }
      });
      //签名合法,包装DO的订单数据
      OrderInfo orderInfo = new OrderInfo();
      BeanUtils.copyProperties(orderInfoVo, orderInfo);
      //覆盖支付方式
      orderInfo.setPayWay(payWay);
      //补全用户ID
      orderInfo.setUserId(AuthContextHolder.getUserId());
      //补全订单no
      orderInfo.setOrderNo(orderInfoVo.getTradeNo());
      //补全订单的描述
      orderInfo.setOrderTitle("声音订单" + itemId);
      //保存订单的数据
      if(orderInfoMapper.insert(orderInfo) <= 0){
        throw new GuiguException(201, "新增订单失败");
      }
      //获取订单id
      Long orderId = orderInfo.getId();
      //保存订单详情
      orderInfoVo.getOrderDetailVoList().stream().forEach(vo->{
        //初始化详情的DO
        OrderDetail orderDetail = new OrderDetail();
        BeanUtils.copyProperties(vo, orderDetail);
        //补全orderId
        orderDetail.setOrderId(orderId);
        //新增
        if(orderDetailMapper.insert(orderDetail) <= 0){
          throw new GuiguException(201, "新增订单失败!!!");
        }
      });
      //保存订单的减免详情
      List<OrderDerateVo> orderDerateVoList =
              orderInfoVo.getOrderDerateVoList();
      if(orderDerateVoList != null){
        orderDerateVoList.stream().forEach(vo->{
          //初始化减免的DO
          OrderDerate orderDerate = new OrderDerate();
          BeanUtils.copyProperties(vo, orderDerate);
          //补全orderId
          orderDerate.setOrderId(orderId);
          //新增
          if(orderDerateMapper.insert(orderDerate) <= 0){
            throw new GuiguException(201, "新增订单失败!!!");
          }
        });
      }
      //返回结果初始化
      JSONObject result = new JSONObject();
      result.put("orderNo", orderInfo.getOrderNo());

      //入库时间点开始,订单支付倒计时:15分钟(10分钟): a.定时任务方案  b.延迟消息方案(最终方案)
      rabbitTemplate.convertAndSend(
              "tingshu_order_exchange",
              "tingshu.order",
              orderId + "",
              message -> {
                //获取消息的属性
                MessageProperties messageProperties = message.getMessageProperties();
                //设置过期时间:毫秒
                messageProperties.setExpiration("900000"); // 900秒(15分钟)
                // messageProperties.setExpiration("20000");
                //返回
                return message;
              });

      //返回
      return result;
    }
    throw new GuiguException(201, "本专辑存在一笔未支付的声音订单");

  }

  @Override
  public Object selectUserOrderPage(Integer page, Integer size) {
    return null;
  }

  @Override
  public OrderInfo getOrderInfo(String orderNo) {
    return null;
  }
}
